package cn.edu.sjtu.se.dslab.component.design.util;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import cn.edu.sjtu.se.dslab.component.design.Button;
import cn.edu.sjtu.se.dslab.component.design.DesignPattern;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternComponent;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternConst;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternType;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.dao.IDesignPatternComponentDao;
import cn.edu.sjtu.se.dslab.helper.ServletContextHelper;
import cn.edu.sjtu.se.dslab.project.BusZone;
import cn.edu.sjtu.se.dslab.project.DisplayZone;
import cn.edu.sjtu.se.dslab.project.EntityZone;
import cn.edu.sjtu.se.dslab.project.EntityZoneCategory;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.project.Variable;
import cn.edu.sjtu.se.dslab.service.IBusZoneService;
import cn.edu.sjtu.se.dslab.service.IButtonService;
import cn.edu.sjtu.se.dslab.service.IDesignPatternComponentService;
import cn.edu.sjtu.se.dslab.service.IDisplayZoneService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneCategoryService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneService;
import cn.edu.sjtu.se.dslab.service.IProjectService;
import cn.edu.sjtu.se.dslab.service.IVariableService;
import cn.edu.sjtu.se.dslab.util.DateUtil;
import cn.edu.sjtu.se.dslab.util.FileUtil;

@Service("designPatternComponentUtil")
public class DesignPatternComponentUtil {
	private static final Logger logger = Logger.getLogger(DesignPatternComponentUtil.class);
	
	@Resource(name = "projectService")
	IProjectService projectService;
	
	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;
	
	@Resource(name = "entityZoneService")
	IEntityZoneService entityZoneService;
	
	@Resource(name="busZoneService")
	IBusZoneService busZoneService;
	
	@Resource(name="displayZoneService")
	IDisplayZoneService displayZoneService;
	
	@Resource(name="buttonService")
	IButtonService buttonService;
	
	@Resource(name="designPatternComponentDao")
	IDesignPatternComponentDao designPatternComponentDao;
	
	@Resource(name="designPatternComponentService")
	IDesignPatternComponentService designPatternComponentService;
	
	@Resource(name="variableService")
	IVariableService variableService;
	
	@Resource(name = "entityZoneCategoryService")
	IEntityZoneCategoryService entityZoneCategoryService;
	
	private long projectId ;
	private long designPatternCategoryId;
	private Project project;
	private Project designPatternCategory;
	
	public void importDesignPatternComponents(long projectId, long designPatternCategoryId){
		Project project = projectService.getProjectById(projectId);
		if (project == null) throw new NullPointerException("No such project exist: id="  + projectId);
		Project designPatternCategory = projectService.getProjectById(designPatternCategoryId);
		if (designPatternCategory == null) throw new NullPointerException("No such designPatternCategory exist: id="  + designPatternCategoryId);
		this.projectId = projectId;
		this.designPatternCategoryId = designPatternCategoryId;
		this.project = project;
		this.designPatternCategory = designPatternCategory;
		importEntityZones();
		importVariables();
		importBusZones();
		importDisplayZones();
		importButtons();
		importDesignPatternComponents();
	}
	
	private void importEntityZones(){
		List<EntityZoneCategory> entityZoneCategorys = entityZoneCategoryService.getEntityZoneCategoryByProject(designPatternCategoryId);
		for (EntityZoneCategory ezc: entityZoneCategorys){
			logger.info("Add entityZone category to project : " + ezc.getName() );
			EntityZoneCategory entityZoneCategory = new EntityZoneCategory();
			entityZoneCategory.setName(ezc.getName());
			entityZoneCategoryService.addEntityZoneCategory(entityZoneCategory, projectId);
		}
		
		List<EntityZone> entityZones = entityZoneService.getEntityZoneByProject(designPatternCategoryId);
		for (EntityZone ez: entityZones){
			logger.info("Add entityZone to project : " + ez.getName() );
			EntityZoneCategory entityZoneCategory = entityZoneCategoryService.getEntityZoneCategoryByProjectAndName(projectId,
					ez.getEntityZoneCategory().getName());
			if (entityZoneCategory != null){
				EntityZone newEntityZone = (EntityZone)ez.clone();
				newEntityZone.setEntityZoneCategory(entityZoneCategory);
				entityZoneService.addEntityZone( newEntityZone, projectId);
			}
		}
	}
	
	private void importVariables(){
		List<Variable> variables = variableService.getVariableByProject(designPatternCategoryId);
		for (Variable v : variables){
			logger.info("Add variable to project: " + v.getName());
			variableService.addVariable((Variable)v.clone(), projectId);
		}
	}
	
	
	private void importButtons(){
		List<Button> buttons = buttonService.getButtonByProject(designPatternCategoryId);
		for (Button button: buttons){
			logger.info("Add button to project : " + button.getName() );
			buttonService.addButton((Button)button.clone(), projectId);
		}
	}
	
	
	private void importDisplayZones(){
		List<DisplayZone> displayZones = displayZoneService.getDisplayZoneByProject(designPatternCategoryId);
		for (DisplayZone dz: displayZones){
			logger.info("Add displayZone to project : " + dz.getName() );
			displayZoneService.addDisplayZone((DisplayZone)dz.clone(), projectId);
		}
	}
	
	private void importBusZones(){
		List<BusZone> busZones = busZoneService.getBusZoneByProject(designPatternCategoryId);
		for (BusZone bz: busZones){
			logger.info("Add busZone to project : " + bz.getName() );
			String[] entityZoneIds = bz.getEntityZones().split("\\|");
			String[] newEntityZoneIds = new String[entityZoneIds.length];
			int index = 0;
			for (String eId: entityZoneIds){
				EntityZone entityZone = entityZoneService.getEntityZoneById(Long.parseLong(eId));
				if (entityZone == null) throw new NullPointerException("No such entityZone id:" + eId);
				EntityZone newEntityZone = entityZoneService.getEntityZoneByProjectAndName(projectId, entityZone.getName());
				newEntityZoneIds[index++] = String.valueOf(newEntityZone.getId());
			}
			BusZone newBusZone = (BusZone)bz.clone();
			newBusZone.addEntityZones(newEntityZoneIds);			
			busZoneService.addBusZone(newBusZone, projectId);
		}
	}
	
	private void importDesignPatternComponents(){
		importBusDesignPatternComponent();
		importIODesignPatternComponent();
		importControlDesignPatternComponent();
		importDisplayDesignPatternComponent();
	}
	
	private void importBusDesignPatternComponent(){
		DesignPatternComponent dpc = 
				designPatternComponentService.getDesignPatternCommponentByType(projectId, DesignPatternType.BUS);
		DesignPatternComponent srcDpc = 
				designPatternComponentService.getDesignPatternCommponentByType(designPatternCategoryId, DesignPatternType.BUS);
		DesignPatternInstanceBean dpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(dpc.getType().toUpperCase()), dpc.getXmlPath());
		DesignPatternInstanceBean srcDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(srcDpc.getType().toUpperCase()), srcDpc.getXmlPath());
		
		List<Map<String, Property>> instances = srcDpiBean.getInstances();
		int maxId = dpiBean.getMaxId();
		for (Map<String, Property> propertyMap: instances){
			Property idProperty = new Property();
			idProperty.setName("id");
			idProperty.setValue( String.valueOf(++maxId));
			propertyMap.put("id", idProperty);
			
			Property busZoneProperty = propertyMap.get("bus_zone");
			BusZone busZone = busZoneService.getBusZoneById(Long.parseLong(busZoneProperty.getValue()));
			if (busZone == null) throw new NullPointerException("No such BusZone id:" + busZoneProperty.getValue());
			BusZone newBusZone = busZoneService.getBusZoneByProjectAndName(projectId, busZone.getName());
			logger.info("Change the bus design pattern component to new busZone:" + newBusZone.getId());
			busZoneProperty.setValue(String.valueOf(newBusZone.getId()));
			dpiBean.getInstances().add(propertyMap);
		}
		dpiBean.setMaxId(maxId);
		dpiBean.save(dpc.getXmlPath());
	}
	
	private void importIODesignPatternComponent(){
		DesignPatternComponent dpc = 
				designPatternComponentService.getDesignPatternCommponentByType(projectId, DesignPatternType.IO);
		DesignPatternComponent srcDpc = 
				designPatternComponentService.getDesignPatternCommponentByType(designPatternCategoryId, DesignPatternType.IO);
		DesignPatternInstanceBean dpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(dpc.getType().toUpperCase()), dpc.getXmlPath());
		DesignPatternInstanceBean srcDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(srcDpc.getType().toUpperCase()), srcDpc.getXmlPath());
		
		List<Map<String, Property>> instances = srcDpiBean.getInstances();
		int maxId = dpiBean.getMaxId();
		for (Map<String, Property> propertyMap: instances){
			Property idProperty = new Property();
			idProperty.setName("id");
			idProperty.setValue( String.valueOf(++maxId));
			propertyMap.put("id", idProperty);
			dpiBean.getInstances().add(propertyMap);
		}
		dpiBean.setMaxId(maxId);
		dpiBean.save(dpc.getXmlPath());
	}
	
	private void importControlDesignPatternComponent(){
		DesignPatternComponent dpc = 
				designPatternComponentService.getDesignPatternCommponentByType(projectId, DesignPatternType.CONTROL);
		DesignPatternComponent srcDpc = 
				designPatternComponentService.getDesignPatternCommponentByType(designPatternCategoryId, DesignPatternType.CONTROL);
		DesignPatternInstanceBean dpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(dpc.getType().toUpperCase()), dpc.getXmlPath());
		DesignPatternInstanceBean srcDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(srcDpc.getType().toUpperCase()), srcDpc.getXmlPath());
		
		List<Map<String, Property>> instances = srcDpiBean.getInstances();
		int maxId = dpiBean.getMaxId();
		for (Map<String, Property> propertyMap: instances){
			Property idProperty = new Property();
			idProperty.setName("id");
			idProperty.setValue( String.valueOf(++maxId));
			propertyMap.put("id", idProperty);
			
			Property buttonProperty = propertyMap.get("button");
			Button button = buttonService.getButtonById(Long.parseLong(buttonProperty.getValue()));
			if (button == null) throw new NullPointerException("No such button id:" + buttonProperty.getValue());
			Button newButton = buttonService.getButtonByProjectAndName(projectId, button.getName());
			logger.info("Change the control design pattern component to use the new button:" + newButton.getId());
			buttonProperty.setValue(String.valueOf(newButton.getId()));
			dpiBean.getInstances().add(propertyMap);
		}
		dpiBean.setMaxId(maxId);
		dpiBean.save(dpc.getXmlPath());
	}
	
	private void importDisplayDesignPatternComponent(){
		DesignPatternComponent dpc = 
				designPatternComponentService.getDesignPatternCommponentByType(projectId, DesignPatternType.DISPLAY);
		DesignPatternComponent srcDpc = 
				designPatternComponentService.getDesignPatternCommponentByType(designPatternCategoryId, DesignPatternType.DISPLAY);
		DesignPatternInstanceBean dpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(dpc.getType().toUpperCase()), dpc.getXmlPath());
		DesignPatternInstanceBean srcDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(srcDpc.getType().toUpperCase()), srcDpc.getXmlPath());
		
		List<Map<String, Property>> instances = srcDpiBean.getInstances();
		int maxId = dpiBean.getMaxId();
		for (Map<String, Property> propertyMap: instances){
			Property idProperty = new Property();
			idProperty.setName("id");
			idProperty.setValue( String.valueOf(++maxId));
			propertyMap.put("id", idProperty);
			
			//处理不同类型的页面
			Property pageType = propertyMap.get(DesignPatternConst.DISPLAY_PAGE_TYPE);
			if (pageType == null) continue;
			if (DesignPattern.DISPLAY_PAGE_ARINC661.equals(pageType.getValue())){
				Property filePath = propertyMap.get(DesignPatternConst.DISPLAY_FILE_PATH);
				Property imagePath = propertyMap.get(DesignPatternConst.DISPLAY_IMAGE_PATH);
				String filePathValue = filePath.getValue();
				String imagePathValue = imagePath.getValue();
				//String realPath = ServletContextHelper.getRealPath();
				String realPath = ServletContextHelper.getServletContext().getRealPath("/");
				logger.info("Servlet Context real path:" + realPath);
				String newScadeDir = "img/upload/" + project.getName() + "/";
				try {
					if (null != filePathValue && "" != filePathValue) {
						File oldfile = new File(realPath + filePathValue);
						if (oldfile.exists()) {
							String originalName = oldfile.getName();
							String postFix = originalName.substring(
									originalName.lastIndexOf('.'),
									originalName.length());
							String newFileName = DateUtil
									.getDateAsFileNameString(DateUtil.COMMON_DATE_PATTERN)
									+ postFix;
							FileUtil.copyFile(realPath + filePathValue,
									realPath + newScadeDir, newFileName);
							filePath.setValue(newScadeDir + newFileName);
						} else {
							filePath.setValue("");
						}
						//propertyMap.put(DesignPatternConst.DISPLAY_FILE_PATH,
								//filePath);
					}
					if (null != imagePathValue && "" != imagePathValue) {
						File oldImageFile = new File(realPath + imagePathValue);
						if (oldImageFile.exists()) {
							String originalName = oldImageFile.getName();
							String postFix = originalName.substring(
									originalName.lastIndexOf('.'),
									originalName.length());
							String newImageName = DateUtil
									.getDateAsFileNameString(DateUtil.COMMON_DATE_PATTERN)
									+ postFix;
							FileUtil.copyFile(realPath + imagePathValue,
									realPath + newScadeDir, newImageName);
							imagePath.setValue(newScadeDir + newImageName);
						} else {
							imagePath.setValue("");
						}
						//propertyMap.put(DesignPatternConst.DISPLAY_IMAGE_PATH,
								//imagePath);
					}
				} catch (IOException ex) {
					logger.error(ex.getStackTrace());
					continue;
				}
			}else if (DesignPattern.DISPLAY_PAGE_USERDEFINED.equals(pageType.getValue())){
				Property pageElement = propertyMap.get("page_elements");
				String elementContent = pageElement.getValue();
				for (Variable v : variableService.getVariableByProject(designPatternCategoryId)){
					Variable newVar = variableService.getVariableByProjectAndName(projectId, v.getName());
					elementContent = elementContent.replace("var_id:" + v.getId() + ",", "var_id:" + newVar.getId() + ",");
				}
				pageElement.setValue(elementContent);
			}else if (DesignPattern.DISPLAY_PAGE_DATA.equals(pageType.getValue())){
				logger.info("Dealing with page data!");
				Property pageVariables = propertyMap.get(DesignPatternConst.DISPLAY_PAGE_VARIABLES);
				String variableContent = pageVariables.getValue();
				logger.info(variableContent);
				String[] variables = variableContent.split("\\|");
				StringBuilder newVar = new StringBuilder();
				for (String var : variables){
					logger.info("Var = " + var);
					StringBuilder sb = new StringBuilder();
					if (var != null && !"".equals(var)) {
						String[] temp = var.split(";");
						DisplayZone originDisplayZone = displayZoneService.getDisplayZoneById(Long.parseLong(temp[1]));
						DisplayZone dz = displayZoneService
								.getDisplayZoneByProjectAndName(projectId, originDisplayZone.getName());
						temp[1] = dz.getId() + "";
						int i = 0;
						for (; i< temp.length -1 ; ++i ){
							sb.append(temp[i]);
							sb.append(";");
						}
						sb.append(temp[i]);
					}
					newVar.append(sb.toString());
					newVar.append("|");
				}
				logger.info("New Page Variable:" + newVar.toString());
				pageVariables.setValue(newVar.toString());
			}
			//arinc661
			dpiBean.getInstances().add(propertyMap);
		}
		dpiBean.setMaxId(maxId);
		dpiBean.save(dpc.getXmlPath());
	}
	
	public void addDpcItem(Map<String, String> propertyMap, String dpcUri){
		DesignPatternComponent dpc = designPatternComponentDao.queryByUri(dpcUri);
		DesignPatternInstanceBean dpiBean = new DesignPatternInstanceBean(
				DesignPatternType.valueOf(dpc.getType().toUpperCase()), dpc.getXmlPath());
		Map<String, Property> instance = new HashMap<String, Property>();
		for (Entry<String, String> entry : propertyMap.entrySet()){
			Property p = new Property();
			p.setName(entry.getKey());
			p.setValue(entry.getValue());
			instance.put(entry.getKey(), p);
		}
		Property idProperty = new Property();
		idProperty.setName("id");
		int newMaxId = dpiBean.getMaxId() + 1;
		idProperty.setValue( String.valueOf(newMaxId));
		dpiBean.setMaxId(newMaxId);
		instance.put("id", idProperty);
		dpiBean.getInstances().add(instance);
		dpiBean.save(dpc.getXmlPath());
	}
	
	
}








